package com.zhangshuo.config;

import java.util.LinkedHashMap;
import java.util.Map;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.zhangshuo.common.shiro.MyDbRealm;
import com.zhangshuo.common.shiro.RetryLimitCredentialsMatcher;
import com.zhangshuo.common.shiro.ShiroSpringCacheManager;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * Created by Administrator on 2017/6/2 0002.
 */
@Configuration
public class ShiroConfig {


    /**
     * 前端集成shiro,就可以直接使用shiro的相关标签
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }


    /**
     * 使用Spring-redis-cacheManager，因为是使用的redis是spring work CacheManager的实现
     * 下面注入错误提示不用理会
     * @param springCacheManager
     * @return
     */
    @Bean
    @Autowired
    public CacheManager getCacheManager(org.springframework.cache.CacheManager springCacheManager){
        CacheManager cacheManager = new ShiroSpringCacheManager(springCacheManager);
        return cacheManager;
    }



    //--------------------------------------remember me Manager -------------------------------------------------------------
    /**
     * 定义remember me 保存的时间
     * @return
     */
    @Bean
    public Cookie cookie(){
        Cookie cookie = new SimpleCookie();
        cookie.setName("rememberMe");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(7*24*60*60);
        return cookie;
    }

    /**
     * 设置remember的管理器
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(Cookie cookie){
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        //设置cookie值
        rememberMeManager.setCookie(cookie);
        //设置编解码的key值，相当于编解码使用相同的规则
        rememberMeManager.setCipherKey("这是我个人的key".getBytes());
        return rememberMeManager;
    }





    //-------------------------------------------------session Manager------------------------------------------------------------
    /**
     * 生成session Dao
     * @param cacheManager
     * @return
     */
    @Bean
    public SessionDAO sessionDAO(CacheManager cacheManager){
        EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
        enterpriseCacheSessionDAO.setCacheManager(cacheManager);
        //保存活跃的session的cache名字，也可以直接从cacheManager中直接获取cache，默认的名字为:shiro-activeSessionCache
        enterpriseCacheSessionDAO.setActiveSessionsCacheName("activeSessionCache");
        return enterpriseCacheSessionDAO;
    }

    @Bean
    public SessionManager sessionManager(SessionDAO sessionDAO){
        //使用容器相关的Session
        //ServletContainerSessionManager sessionManager = new ServletContainerSessionManager();
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //全局的session存活时间
        sessionManager.setGlobalSessionTimeout(1000L * 60 * 60);
        //没有找到取消sessionId的去除方法，随后再看
        //TODO
        sessionManager.setSessionDAO(sessionDAO);
        return sessionManager;
    }




//-------------------------------------------------ream设置--------------------------------------------------------------
    @Bean
    public RetryLimitCredentialsMatcher retryLimitCredentialsMatcher(CacheManager cacheManager){

        //因为初始化cache是在构造方法中的，所以把参数直接传过去
        //或者使用IntatialzingBean的接口在属性设置完成后赋值
        RetryLimitCredentialsMatcher  retryLimitCredentialsMatcher = new RetryLimitCredentialsMatcher(cacheManager,"oneDay");
        //做哈希的次数，可以使用多次，默认为1次
        retryLimitCredentialsMatcher.setHashIterations(1);
        //在这里定义加密的方式
        retryLimitCredentialsMatcher.setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
        //不建议在这里设置slat的值，因为大部分的盐值均为用户相关的，所以将设置放到Token中或info中均可
        //先从info中去找，因为SimpleAuthenticationInfo是SaltedAuthenticationInfo子类，所以直接从info去查找salt;

        //默认以HEX进行编码,如果设置为false，则表明为Base64的方式
        retryLimitCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return retryLimitCredentialsMatcher;
    }

    @Bean
    public MyDbRealm realm(CacheManager cacheManager, RetryLimitCredentialsMatcher retryLimitCredentialsMatcher){

        MyDbRealm myDbRealm = new MyDbRealm(cacheManager,retryLimitCredentialsMatcher);

        return myDbRealm;
    }








//--------------------------------------securtiy manager-----------------------------------------------

    @Bean
    public DefaultWebSecurityManager webSecurityManager(CacheManager cacheManager,RememberMeManager rememberMeManager,SessionManager sessionManager,MyDbRealm realm){
        DefaultWebSecurityManager  webSecurityManager = new DefaultWebSecurityManager();
        //缓存管理器
        webSecurityManager.setCacheManager(cacheManager);
        //记住我的管理器
        webSecurityManager.setRememberMeManager(rememberMeManager);
        //校验管理器
        webSecurityManager.setRealm(realm);
        //session管理器
        webSecurityManager.setSessionManager(sessionManager);
        return webSecurityManager;
    }




    //---------------------shiro filter Factory bean --------------------------------------------------------------------------
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(WebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/login");
        //定义访问规则
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap();
        filterChainDefinitionMap.put("/img/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/login","anon");
        filterChainDefinitionMap.put("/**", "user");
        //暂时放开所有的权限
//        filterChainDefinitionMap.put("/**", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }





}
